package cn.maihe.elg.operation.supports.electronicseal.jd;

import cn.maihe.elg.operation.model.bo.GuaranteeTemplatePdfParams;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.GuaranteeTemplateType;
import cn.maihe.elg.operation.model.enums.SignatureFileTypeEnum;
import cn.maihe.elg.operation.repository.entity.AcceptOrderInfoDO;
import cn.maihe.elg.operation.repository.entity.BidCustomerDO;
import cn.maihe.elg.operation.repository.entity.GuaranteeInstitutionDO;
import cn.maihe.elg.operation.repository.entity.ProjectInfoDO;
import cn.maihe.elg.operation.supports.electronicseal.jd.config.JDSignatureConfig;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.req.DownloadSignatureFileReqDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.req.FileSignatureReqDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.req.FilesInfo;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.req.GenerateSignatureFileReqDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.req.SignatureAttachment;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.req.UploadAssembleOfdFileReqDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.req.UploadPendingSignatureFileReqDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.resp.FileSignatureRespDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.resp.FileSignatureResult;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.resp.GenerateSignatureFileRespDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.resp.GenerateSignatureFileResult;
import cn.maihe.elg.operation.supports.electronicseal.jd.dto.resp.JDOfdSignatureBaseDTO;
import cn.maihe.elg.operation.supports.electronicseal.jd.service.impl.JDSignatureServiceImpl;
import cn.maihe.elg.operation.supports.system.ElgResourceService;
import cn.maihe.elg.operation.utils.CreateGuaranteeUtil;
import cn.maihe.elg.operation.utils.CurrencyUpperUtil;
import cn.maihe.elg.operation.utils.DocFillUtil;
import cn.maihe.elg.operation.utils.IdGenerate;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class JDSignatureSupport {

    @Resource
    private JDSignatureServiceImpl jdSignatureServiceImpl;

    @Resource
    private JDSignatureConfig jdSignatureConfig;

    @Resource
    private ElgResourceService elgResourceService;

    public Path getSignatureFile(SignatureFileTypeEnum signatureFileTypeEnum,
                                 GuaranteeInstitutionDO guaranteeInstitutionDO,
                                 CenterNoEnum centerNoEnum,
                                 AcceptOrderInfoDO acceptOrderInfoDO,
                                 ProjectInfoDO projectInfoDO,
                                 BidCustomerDO bidCustomerDO,
                                 GuaranteeTemplatePdfParams pdfParams,
                                 ArrayList<SignatureAttachment> signatureAttachments){
        String acceptOrderNo = acceptOrderInfoDO.getAcceptOrderNo();

        String subPath,fileName, fileType;
        if(SignatureFileTypeEnum.PDF.equals(signatureFileTypeEnum) ){
            subPath = "ofd";
            fileName = "guaranteePdfUnSeal";
            fileType = "pdf";
        } else {
            subPath = "ofd";
            fileName = "unSeal担保保函";
            fileType = "pdf";
        }

        //未签章pdf文件存储路径
        Path targetPdfPath = elgResourceService.buildSaveAbsolutePath(subPath, acceptOrderNo, fileName, fileType);
        //担保保函模板填充后docx文件
        Path sourceDocxPath = elgResourceService.buildGuaranteeFileByTemplate(acceptOrderNo, pdfParams);
        //docx转pdf
        DocFillUtil.doc2pdf(sourceDocxPath, targetPdfPath, null);
        this.deleteTmpFile(sourceDocxPath);

        String orderId = IdGenerate.get32UUID();
        JDOfdSignatureBaseDTO jdOfdSignatureBaseDTO;
        if(SignatureFileTypeEnum.PDF.equals(signatureFileTypeEnum) ){
            // 1:上传待签章文件
            try (FileInputStream fis = new FileInputStream(targetPdfPath.toFile())) {

                MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
                // 1. 封装文件流
                InputStreamResource resource = new InputStreamResource(fis) {
                    @Override
                    public String getFilename() {
                        return "file";
                    }
                    @Override
                    public long contentLength() throws IOException {
                        return fis.available();
                    }
                };
                body.add("file",resource);

                body.add("orderId",orderId);
                body.add("name",fileName);
                body.add("fileName",fileName + "." + fileType);
                String fileMd5 = DigestUtils.md5Hex(Files.readAllBytes(targetPdfPath));
                body.add("fileMd5",fileMd5);

                UploadPendingSignatureFileReqDTO uploadPendingSignatureFileReqDTO = new UploadPendingSignatureFileReqDTO();
                uploadPendingSignatureFileReqDTO.setOrderId(orderId);
                uploadPendingSignatureFileReqDTO.setName(fileName);
                uploadPendingSignatureFileReqDTO.setFileName(fileName + "." + fileType);
                uploadPendingSignatureFileReqDTO.setFileMd5(fileMd5);

                if(SignatureFileTypeEnum.OFD.equals(signatureFileTypeEnum) && CreateGuaranteeUtil.isXiaMen(centerNoEnum) ){
                    String letterNo = acceptOrderInfoDO.getGuaranteeNo();
                    String issuerCode = guaranteeInstitutionDO.getGuarantorCreditCode();
                    String issuerName = guaranteeInstitutionDO.getGuarantorName();

                    body.add("type",jdSignatureConfig.getType());
                    body.add("letterNo",letterNo);
                    body.add("issuerCode",issuerCode);
                    body.add("issuerName",issuerName);

                    uploadPendingSignatureFileReqDTO.setType(jdSignatureConfig.getType());
                    uploadPendingSignatureFileReqDTO.setLetterNo(letterNo);
                    uploadPendingSignatureFileReqDTO.setIssuerCode(issuerCode);
                    uploadPendingSignatureFileReqDTO.setIssuerName(issuerName);
                }

                jdOfdSignatureBaseDTO = jdSignatureServiceImpl.uploadPendingSignatureFile(jdSignatureConfig.getPdfBaseUrl()+"dpf",uploadPendingSignatureFileReqDTO,body);
            } catch (Exception e) {
                log.error("uploadPendingSignatureFile error"+e.getMessage(), e);
                jdOfdSignatureBaseDTO = null;
            }
        }else {
            List<FileInputStream> fileInputStreams = new ArrayList<>();
            try (FileInputStream fis = new FileInputStream(targetPdfPath.toFile())) {
                MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();

                List<FilesInfo> filesInfos = new ArrayList<>();
                FilesInfo file =  new FilesInfo();
                file.setFileKey("file");
                file.setFileName(fileName + "." + fileType);
                String fileMd5 = DigestUtils.md5Hex(Files.readAllBytes(targetPdfPath));
                file.setFileMd5(fileMd5);
                file.setFileType("1");
                filesInfos.add(file);

                InputStreamResource resource = new InputStreamResource(fis) {
                    @Override
                    public String getFilename() {
                        return "file";
                    }
                    @Override
                    public long contentLength() throws IOException {
                        return fis.available();
                    }
                };
                body.add("file",resource);

                if(CollectionUtils.isNotEmpty(signatureAttachments)){
                    int size = signatureAttachments.size();
                    for (int i = 0; i < size; i++) {
                        SignatureAttachment signatureAttachment = signatureAttachments.get(i);
                        String title = signatureAttachment.getTitle();
                        String type = signatureAttachment.getType();
                        FilesInfo filesInfo =  new FilesInfo();
                        filesInfo.setFileKey("file"+i);
                        filesInfo.setFileName(title+"."+type);
                        filesInfo.setFileMd5(DigestUtils.md5Hex(Files.newInputStream(signatureAttachment.getPath())));
                        filesInfo.setFileType("2");
                        filesInfos.add(filesInfo);

                        FileInputStream inputStream = new FileInputStream(signatureAttachment.getPath().toFile());
                        fileInputStreams.add(i,inputStream);
                        InputStreamResource signatureAttachmentInputStream = new InputStreamResource(inputStream) {
                            @Override
                            public String getFilename() {
                                return filesInfo.getFileKey();
                            }
                            @Override
                            public long contentLength() throws IOException {
                                return inputStream.available();
                            }
                        };
                        body.add(filesInfo.getFileKey(),signatureAttachmentInputStream);
                    }
                }

                String filesInfosToString = JSON.toJSONString(filesInfos);

                body.add("orderId",orderId);
                body.add("name",fileName);
                body.add("filesInfo",filesInfosToString);

                UploadAssembleOfdFileReqDTO uploadAssembleOfdFileReqDTO =  new UploadAssembleOfdFileReqDTO();
                uploadAssembleOfdFileReqDTO.setOrderId(orderId);
                uploadAssembleOfdFileReqDTO.setName(fileName);
                uploadAssembleOfdFileReqDTO.setFilesInfo(filesInfosToString);

                if(SignatureFileTypeEnum.OFD.equals(signatureFileTypeEnum) && CreateGuaranteeUtil.isXiaMen(centerNoEnum)){
                    String docId = acceptOrderInfoDO.getCenterOrderId();
                    String customDatas = JSON.toJSONString(assembleMetas(guaranteeInstitutionDO, acceptOrderInfoDO, projectInfoDO, bidCustomerDO));
                    String letterNo = acceptOrderInfoDO.getGuaranteeNo();
                    String issuerCode = guaranteeInstitutionDO.getGuarantorCreditCode();
                    String issuerName = guaranteeInstitutionDO.getGuarantorName();

                    body.add("type",jdSignatureConfig.getType());
                    body.add("docId",docId);
                    body.add("customDatas",customDatas);
                    body.add("letterNo",letterNo);
                    body.add("issuerCode",issuerCode);
                    body.add("issuerName",issuerName);

                    uploadAssembleOfdFileReqDTO.setType(jdSignatureConfig.getType());
                    uploadAssembleOfdFileReqDTO.setDocId(docId);
                    uploadAssembleOfdFileReqDTO.setCustomDatas(customDatas);
                    uploadAssembleOfdFileReqDTO.setLetterNo(letterNo);
                    uploadAssembleOfdFileReqDTO.setIssuerCode(issuerCode);
                    uploadAssembleOfdFileReqDTO.setIssuerName(issuerName);
                }
                jdOfdSignatureBaseDTO = jdSignatureServiceImpl.uploadAssembleOfdFile(jdSignatureConfig.getOfdBaseUrl()+"dpof",uploadAssembleOfdFileReqDTO, body);
            } catch (Exception e) {
                log.error("uploadAssembleOfdFile error"+e.getMessage(), e);
                jdOfdSignatureBaseDTO = null;
            }   finally {
                for (FileInputStream fileInputStream : fileInputStreams){
                    try {
                        if(Objects.nonNull(fileInputStream)){
                            fileInputStream.close();
                        }
                    } catch (IOException e) {
                        log.error("ofd fileInputStream close error"+e.getMessage(), e);
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        if(Objects.isNull(jdOfdSignatureBaseDTO) || !jdOfdSignatureBaseDTO.getSuccess()){
            String msg = "待签署文件上传异常";
            log.error(msg);
            throw new RuntimeException(msg);
        }
        GuaranteeTemplateType guaranteeTemplateType = pdfParams.getGuaranteeTemplateType();

        // 2:文件签章
        String [] devGroupIds;
        // 先企业签章 再个人签章
        if(SignatureFileTypeEnum.PDF.equals(signatureFileTypeEnum)){
            devGroupIds = jdSignatureConfig.getPdfDevGroupIds();
        } else {
            devGroupIds = jdSignatureConfig.getOfdDevGroupIds();
        }

        if(Objects.isNull(devGroupIds) || devGroupIds.length != 2){
            String msg = "证书印章信息配置错误";
            log.error(msg);
            throw new RuntimeException(msg);
        }

        int length = devGroupIds.length;
        for (int i = 0; i < length; i++) {
            String devGroupId = devGroupIds[i];
            log.info("getSignatureFile devGroupIds:{}",devGroupId);
            String pages,sealX,sealY;
            if(i == 0){
                pages = Integer.toString(guaranteeTemplateType.getSignPageNum()+1);
                sealX = guaranteeTemplateType.getSignOrgXpx().toString();
                sealY = guaranteeTemplateType.getSignOrgYpx().toString();
            }else {
                pages = Integer.toString(guaranteeTemplateType.getSignPageNum()+1);
                sealX = guaranteeTemplateType.getSignLegalXpx().toString();
                sealY = guaranteeTemplateType.getSignLegalYpx().toString();
            }

            MultiValueMap<String, Object> fileSignatureBody = new LinkedMultiValueMap<>();
            fileSignatureBody.add("orderIds",orderId);
            fileSignatureBody.add("pages",pages);
            fileSignatureBody.add("sealX",sealX);
            fileSignatureBody.add("sealY",sealY);
            fileSignatureBody.add("devGroupIds",devGroupId);

            FileSignatureReqDTO fileSignatureReqDTO = new FileSignatureReqDTO();
            fileSignatureReqDTO.setOrderIds(orderId);
            fileSignatureReqDTO.setPages(pages);
            fileSignatureReqDTO.setSealX(sealX);
            fileSignatureReqDTO.setSealY(sealY);
            fileSignatureReqDTO.setDevGroupIds(devGroupId);
            String fileSignatureUrl = SignatureFileTypeEnum.PDF.equals(signatureFileTypeEnum)?jdSignatureConfig.getPdfBaseUrl()+"sdp":jdSignatureConfig.getOfdBaseUrl()+"sdo";
            FileSignatureRespDTO fileSignatureRespDTO = jdSignatureServiceImpl.fileSignature(fileSignatureUrl,fileSignatureReqDTO,fileSignatureBody);
            if(Objects.isNull(fileSignatureRespDTO) || !fileSignatureRespDTO.getSuccess()){
                String msg = "文件签章异常";
                log.error(msg);
                throw new RuntimeException(msg);
            }
            List<FileSignatureResult> fileSignatureResults = fileSignatureRespDTO.getResult();
            if(CollectionUtils.isEmpty(fileSignatureResults)){
                String msg = "获取文件签章结果列表失败";
                log.error(msg);
                throw new RuntimeException(msg);
            }
            FileSignatureResult fileSignatureResult = fileSignatureResults.get(0);
            if(Objects.isNull(fileSignatureResult) || !fileSignatureResult.getSuccess()){
                String msg = "获取文件签章结果失败";
                log.error(msg);
                throw new RuntimeException(msg);
            }
        }

        // 3:生成签章文件
        MultiValueMap<String, Object> generateSignatureFileBody = new LinkedMultiValueMap<>();
        generateSignatureFileBody.add("orderIds",orderId);

        GenerateSignatureFileReqDTO generateSignatureFileReqDTO = new GenerateSignatureFileReqDTO();
        generateSignatureFileReqDTO.setOrderIds(orderId);
        String generateSignatureFileUrl = SignatureFileTypeEnum.PDF.equals(signatureFileTypeEnum)?jdSignatureConfig.getPdfBaseUrl()+"cfd":jdSignatureConfig.getOfdBaseUrl()+"cfd";
        GenerateSignatureFileRespDTO generateSignatureFileRespDTO = jdSignatureServiceImpl.generateSignatureFile(generateSignatureFileUrl,generateSignatureFileReqDTO,generateSignatureFileBody);
        if(Objects.isNull(generateSignatureFileRespDTO) || !generateSignatureFileRespDTO.getSuccess()){
            String msg = "生成签章文件异常";
            log.error(msg);
            throw new RuntimeException(msg);
        }
        List<GenerateSignatureFileResult> generateSignatureFileResults = generateSignatureFileRespDTO.getResult();
        if(CollectionUtils.isEmpty(generateSignatureFileResults)){
            String msg = "获取生成签章文件列表失败";
            log.error(msg);
            throw new RuntimeException(msg);
        }
        GenerateSignatureFileResult generateSignatureFileResult = generateSignatureFileResults.get(0);
        if(Objects.isNull(generateSignatureFileResult) || !generateSignatureFileResult.getSuccess()){
            String msg = "获取生成签章文件结果失败";
            log.error(msg);
            throw new RuntimeException(msg);
        }

        // 4:下载签章文件
        MultiValueMap<String, Object> downloadSignatureFileBody = new LinkedMultiValueMap<>();
        downloadSignatureFileBody.add("orderId",orderId);

        Path targetSealPath;
        if(SignatureFileTypeEnum.PDF.equals(signatureFileTypeEnum) ){
            // 签章后的pdf文件
            targetSealPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "guaranteePdfSeal", "pdf");
        }else {
            // 签章后的odf文件
            targetSealPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, acceptOrderInfoDO.getGuaranteeNo(), "ofd");
        }
        DownloadSignatureFileReqDTO downloadSignatureFileReqDTO = new DownloadSignatureFileReqDTO();
        downloadSignatureFileReqDTO.setOrderId(orderId);
        String downloadSignatureFileUrl = SignatureFileTypeEnum.PDF.equals(signatureFileTypeEnum)?jdSignatureConfig.getPdfBaseUrl()+"dlfp":jdSignatureConfig.getOfdBaseUrl()+"dlfp";
        return jdSignatureServiceImpl.downloadSignatureFile(downloadSignatureFileUrl,downloadSignatureFileReqDTO,targetSealPath.toAbsolutePath().toString(),downloadSignatureFileBody);
    }

    private Map<String, String> assembleMetas(GuaranteeInstitutionDO guaranteeInstitutionDO,AcceptOrderInfoDO acceptOrderInfoDO, ProjectInfoDO projectInfoDO, BidCustomerDO bidCustomerDO){
        Map<String, String> metas = new HashMap<>();
        metas.put("电子投标保函编号", acceptOrderInfoDO.getGuaranteeNo());
        metas.put("担保额度", CurrencyUpperUtil.fenToYuanNum(projectInfoDO.getBidBond()));
        metas.put("保费", CurrencyUpperUtil.fenToYuan(acceptOrderInfoDO.getGuaranteeFee()));
        metas.put("招标项目编号", projectInfoDO.getProjectCode());
        metas.put("招标项目名称", projectInfoDO.getProjectName());
        metas.put("标段编号", projectInfoDO.getSectionCode());
        metas.put("标段名称", projectInfoDO.getSectionName());
        metas.put("投标人名称", bidCustomerDO.getBidderName());
        metas.put("投标人统一社会信用代码", bidCustomerDO.getBidderCreditCode());
        metas.put("招标人名称", projectInfoDO.getTenderer());
        metas.put("招标人统一社会信用代码", projectInfoDO.getTendererCreditCode());
        metas.put("工程担保保证人名称", guaranteeInstitutionDO.getGuarantorName());
        metas.put("工程担保保证人统一社会信用代码", guaranteeInstitutionDO.getGuarantorCreditCode());
        return metas;
    }

    private void deleteTmpFile(Path... tmpPath) {
        if (tmpPath != null && tmpPath.length != 0) {
            Arrays.stream(tmpPath).forEach(tmp -> {
                try {
                    Files.deleteIfExists(tmp);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}
